package org.framework.server.service;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;

import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.framework.core.Configation;
import org.framework.core.error.support.Errors;
import org.framework.core.util.DateUtil;
import org.framework.core.util.FileUtil;
import org.framework.core.util.HttpUtil;
import org.framework.core.util.StringUtil;
import org.framework.core.validate.annotation.Parameter;
import org.framework.core.validate.annotation.ServiceMethod;
import org.framework.core.validate.support.param.DateTimeParam;
import org.framework.core.validate.support.param.NumberParam;
import org.framework.core.web.handler.ServiceHandler;
import org.framework.define.Constant;
import org.framework.define.DateFormat;
import org.framework.define.bean.entity.TblTask;
import org.framework.define.bean.entity.TblTaskBidder;
import org.framework.define.bean.entity.TblTaskBidderPK;
import org.framework.define.bean.entity.TblTaskIpLimit;
import org.framework.define.bean.entity.TblTaskProductLimit;
import org.framework.define.bean.entity.TblTaskProductLimitPK;
import org.framework.define.bean.entity.TblTaskStoreLimit;
import org.framework.define.bean.entity.TblTaskStoreLimitPK;
import org.framework.define.bean.entity.TblTaskTypeLimit;
import org.framework.define.bean.entity.TblTaskTypeLimitPK;
import org.framework.define.bean.entity.TblUser;
import org.framework.define.bean.entity.TblUserAccount;
import org.framework.define.bean.entity.TblUserBizAccount;
import org.framework.define.bean.entity.TblUserProgress;
import org.framework.define.bean.medium.JsonAddress;
import org.framework.define.bean.medium.JsonIPInfo;
import org.framework.define.bean.medium.JsonProduct;
import org.framework.define.bean.medium.JsonReceiveAddress;
import org.framework.define.bean.medium.JsonSellerPrompt;
import org.framework.define.bean.medium.JsonShow;
import org.framework.define.bean.result.Result;
import org.framework.define.bean.result.criteria.Data;
import org.framework.define.bean.result.criteria.DataResult;
import org.framework.define.bean.result.stream.StreamData;
import org.framework.define.bean.result.stream.StreamResult;
import org.framework.define.error.CustomErrors;
import org.framework.define.mapper.support.BidderRowMapper;
import org.framework.define.mapper.support.UserAccountRowMapper;
import org.framework.define.param.PageParam;
import org.framework.define.param.SortParam;
import org.framework.define.param.TenMultipleParam;
import org.framework.define.param.TokenParam;
import org.framework.define.param.enums.TaskPublishTypeEParam;
import org.framework.define.param.enums.TaskStateEParam;
import org.framework.define.param.enums.TaskTypeEParam;
import org.framework.server.memory.Memory;
import org.framework.server.util.TaskUtil;
import org.framework.server.util.UserUtil;
import org.framework.server.util.dao.IServiceDao;
import org.framework.server.util.dao.sql.Logic;
import org.framework.server.util.dao.sql.support.Condition;
import org.framework.server.util.dao.sql.support.Profile;
import org.framework.server.util.dao.sql.support.QueryBuilder;
import org.framework.server.util.dao.sql.support.filter.SqlColumn;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("task")
public class TaskService extends ServiceHandler {
	
	@Autowired
	protected IServiceDao serviceDao;
	
	private ObjectMapper mapper = new ObjectMapper();
	{
		mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
		mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
	}
	
	@ServiceMethod(
		value="getProductInfo",
		desc="获取商品信息",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter("url")
		}
	)
	public Result getProductInfo(HttpServletRequest request, Map<String,String> params) {
		JsonProduct product = new JsonProduct();
		try {
			String url = URLDecoder.decode(params.get("url"), "utf-8");
			product = TaskUtil.shopCrawler(url);
		} catch (Exception e) {
			return new Result(Errors.EXCEPTION_UNKNOW);
		}
		return new DataResult(Errors.OK, new Data(product));
	}
	
	@ServiceMethod(
		value="uploadShowImg",
		desc="上传晒单图片",
		params={
			@Parameter(type=TokenParam.class)
		}
	)
	public Result uploadShowImg(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		String imageUrl = null;
		try {
			Part part = request.getPart("file");
			String type = part.getContentType();
			String disposition = part.getHeader("content-disposition");
			
			if(!type.contains("image/"))
				return new DataResult(Errors.DATA_TYPE_ERROR);
			
			String image = UUID.randomUUID().toString().replace("-", "") + disposition.substring(disposition.lastIndexOf("."), disposition.length() -1);
			String path = Configation.getSysProp("sys.filePath") + "/" + sessionUser.getUserId();

			FileUtil.createDirs(path, true);
			System.out.println(path + "/" + image);
			
			
			StreamData data = new StreamData();
			data.setInfo(FileUtil.getByteOutputStream(part.getInputStream()));
			
			part.write(path + "/" + image);
			
			imageUrl = "http://" + request.getServerName() + ":" +request.getServerPort() + path.substring(path.indexOf(":") + 1) + image;
			return new StreamResult(Errors.OK, data);
		} catch (IllegalStateException | IOException | ServletException e) {
			e.printStackTrace();
		}
		return new DataResult(Errors.OK, new Data(imageUrl));
	}
	
	@ServiceMethod(
		value="removeShowImg",
		desc="删除晒单图片",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter("fileName")
		}
	)
	public Result removeShowImg(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		
		String path = Configation.getSysProp("sys.filePath") + "/" + sessionUser.getUserId();
		String image = path + "/" + params.get("fileName");
		try {
			FileUtil.deleteFile(image);
		} catch (IOException e) {
			e.printStackTrace();
			return new DataResult(Errors.DATA_NOT_EXIST);
		}
		
		return new DataResult(Errors.OK);
	}
	
	@ServiceMethod(
		value="getTasklist",
		desc="获取任务列表",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter(type=PageParam.class),
			@Parameter(type=SortParam.class),
			@Parameter(value="state", type=TaskStateEParam.class, defaultValue=Constant.Task.State.WAIT, desc="任务状态"),
		}
	)
	public Result getTasklist(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		
		QueryBuilder builder = new QueryBuilder(
			"select * from tbl_task",
			new Condition(
				new SqlColumn(Logic.WHERE, "user_id").equal(sessionUser.getUserId()),
				new SqlColumn("task_state").equal(params.get("state"))
			),
			new Profile(params)
		);
		
		DataResult result = serviceDao.queryForDataResult(builder, TblTask.class);

		return result;
	}
	
	@ServiceMethod(
		value="addTask",
		desc="发布任务",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter(value="type", type=TaskTypeEParam.class, desc="任务类型"),
			@Parameter(value="keyword", required=false, desc="搜索关键字"),
			@Parameter(value="tip", required=false, desc="搜索提示"),
			@Parameter(value="image_tip", required=false, desc="图片提示"),
			@Parameter(value="seller", desc="卖家掌柜名"),
			@Parameter(value="product", desc="商品信息 格式:[{price:10, url:'http://...'}, {...}]"),
			@Parameter(value="modify_price", required=false, enums={"1"}, desc="是否需要改价"),
			@Parameter(value="append_coins", required=false, type=NumberParam.class, desc="是否追加金币"),
			@Parameter(value="publish_type", type=TaskPublishTypeEParam.class, desc="发布类型"),
			@Parameter(value="score", required=false, enums={"1"}, desc="是否需要商品评分"),
			@Parameter(value="prompt", required=false, desc="卖家提醒语 格式:{}"),
			@Parameter(value="comment", required=false, desc="是否规定评论内容"),
			@Parameter(value="show", required=false, desc="是否规定晒单 格式:{}"),
			@Parameter(value="append_cmt", enums={"1"}, required=false, desc="是否规定追加评论"),
			@Parameter(value="append_show", required=false, desc="是否规定追评晒单 格式:{}"),
			@Parameter(value="tb_coins", required=false, type=TenMultipleParam.class, desc="是否需要淘金币 格式:10的倍数"),
			@Parameter(value="receive_addr", required=false, desc="是否规定收货地址 格式:{}"),
			@Parameter(value="share", enums={"1", "2"}, required=false, desc="是否需要分享"),
			@Parameter(value="real", enums={"1"}, required=false, desc="是否要求买号实名"),
			@Parameter(value="check", enums={"1"}, required=false, desc="是否需要审核"),
			@Parameter(value="safe", enums={"1"}, required=false, desc="是否需要平台认证"),
			@Parameter(value="chat", enums={"1"}, required=false, desc="是否需要旺旺聊天"),
			@Parameter(value="received", enums={"1", "2"}, required=false, desc="是否要求真实签收"),
			@Parameter(value="take_addr", required=false, desc="是否指定接任务地区 格式:{}"),
			@Parameter(value="compare", enums={"1"}, required=false, desc="是否要求货比三家"),
			@Parameter(value="channel", enums={"1"}, required=false, desc="是否要求购买渠道"),
			@Parameter(value="postTime", required=false, type=DateTimeParam.class, desc="发布时间[不传此参数则立即发布]"),
			
		}
	)
	public Result addTask(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		
		TblUserAccount account = serviceDao.get(TblUserAccount.class, sessionUser.getUserId());
		
		//最低消耗
		BigDecimal lowest = new BigDecimal(0);
		//支付给买家金币
		BigDecimal payCoins = new BigDecimal(0);
		//平台消耗金币
		BigDecimal spendCoins = new BigDecimal(0);
		
		StringBuffer icoStr = new StringBuffer("");
		
		TblTask task = new TblTask();
		task.setTaskId(TaskUtil.generateTaskId());
		task.setUserId(sessionUser.getUserId());
		task.setType(Integer.parseInt(params.get("type")));
		task.setSearchKeyword(params.get("keyword"));
		task.setSearchTip(params.get("tip"));
		task.setSearchImageTip(params.get("image_tip"));
		task.setBuyerSecurityDeposit(new BigDecimal(0));
		task.setPostIp(HttpUtil.getRemoteAddress(request));
		task.setTaskState(Constant.Task.State.WAIT);
		
		String seller = params.get("seller");
		//验证卖号是否存在
		int count = serviceDao.count(
			"select count(0) from tbl_user_biz_account where user_id=? and biz_account=? and biz_type=?",
			new Object[]{sessionUser.getUserId(), seller, Constant.User.BizAccount.Type.SELLER}
		);
		if(count == 0)
			return new Result(CustomErrors.USER_BIZACCOUNT_ERROR_NOT_EXIST);
		task.setSellerBizAccount(seller);
		
		
		//设置 商品信息
		String productInfo = params.get("product");
		try {
			List<JsonProduct> productList = mapper.readValue(productInfo, new TypeReference<List<JsonProduct>>(){});
			
			//计算保证金
			BigDecimal price = new BigDecimal(0);
			for (JsonProduct jsonProduct : productList) {
				if(jsonProduct.getUrl() == null)
					return new Result(Errors.PARAM_FORMAT_ERROR, MessageFormat.format(Errors.PARAM_FORMAT_ERROR.getMsg(), "product.url"));
				
				JsonProduct product = TaskUtil.shopCrawler(jsonProduct.getUrl());
				
				jsonProduct.setSeller(seller);
				jsonProduct.setShopId(product.getShopId());
				
				//判断商品与掌柜是否匹配
				if(product.getSeller() != null && !product.getSeller().equals(seller))
					return new Result(CustomErrors.TASK_ERROR_ACCOUNT_NOT_MATCH);
				
				if(jsonProduct.getPrice() == null){
					if(product.getPrice() == null)
						return new Result(Errors.PARAM_FORMAT_ERROR, MessageFormat.format(Errors.PARAM_FORMAT_ERROR.getMsg(), "product.price"));
					jsonProduct.setPrice(product.getPrice());
				}
				if(jsonProduct.getName() == null)
					jsonProduct.setName(product.getName());
				if(jsonProduct.getImgUrl() == null)
					jsonProduct.setImgUrl(product.getImgUrl());
				
				
				price = price.add(jsonProduct.getPrice());
			}
			productInfo = mapper.writeValueAsString(productList);
			//判断余额
			if(account.getBalance().compareTo(price) == -1)
				return new Result(CustomErrors.USER_ACCOUNT_ERROR_BALANCE_NOT_ENOUGH);
			//扣除相应余额转为平台任务保障金
			account.setBalance(account.getBalance().subtract(price));
			task.setSellerSecurityDeposit(price);
			
			//根据商品价格计算最低消耗金币
			lowest = TaskUtil.countLowestCoins(price);
			
		} catch (IOException e) {
			e.printStackTrace();
			return new Result(Errors.PARAM_FORMAT_ERROR, MessageFormat.format(Errors.PARAM_FORMAT_ERROR.getMsg(), "product"));
		} catch (Exception e) {
			e.printStackTrace();
			return new Result(CustomErrors.TASK_ERROR_PRODUCT);
		}
		task.setProductInfo(productInfo);
		
		//设置 是否改价
		String modifyPrice = params.get("modify_price");
		if(modifyPrice != null){
			icoStr.append(Constant.Task.Rule.Ico.PRICE).append(",");
			task.setNeedModifyPrice(modifyPrice);
		}
		
		//设置 追加金币
		String appendCoinsStr = params.get("append_coins");
		if(appendCoinsStr != null){
			BigDecimal appendCoins = new BigDecimal(appendCoinsStr);
			task.setAppendCoins(appendCoins);
			payCoins.add(appendCoins);
		}
		
		
		//设置 发布类型
		String publishTpe = params.get("publish_type");
		//计算 发布类型 消耗金币
		TaskUtil.countRuleCoins(publishTpe, payCoins, spendCoins, lowest);
		task.setPublishType(publishTpe);
		
		//设置 是否要求评分
		String score = params.get("score");
		if(score != null){
			task.setProductScore(params.get("score"));
		}
		
		
		//设置 卖家提醒语
		String sellerPrompt = params.get("prompt");
		if(sellerPrompt != null){
			//计算 卖家提醒语 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.PROMPT, payCoins, spendCoins, lowest);
			try {
				sellerPrompt = mapper.writeValueAsString(mapper.readValue(sellerPrompt, JsonSellerPrompt.class));
			} catch (IOException e) {
				return new Result(Errors.PARAM_FORMAT_ERROR, MessageFormat.format(Errors.PARAM_FORMAT_ERROR.getMsg(), "prompt"));
			}
			task.setSellerPrompt(sellerPrompt);
		}
		
		
		//设置 是否规定评论内容
		String comment = params.get("comment");
		if(comment != null){
			task.setNeedComment(comment);
		}
		
		//设置 是否要求晒单
		String show = params.get("show");
		if(show != null){
			//计算 晒单 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.SHOW, payCoins, spendCoins, lowest);
			try {
				show = mapper.writeValueAsString(mapper.readValue(show, JsonShow.class));
			} catch (IOException e) {
				return new Result(Errors.PARAM_FORMAT_ERROR, MessageFormat.format(Errors.PARAM_FORMAT_ERROR.getMsg(), "show"));
			}
			task.setNeedShow(show);
		}
				
		//设置 是否要求追加评论
		String appendCmt = params.get("append_cmt");
		if(appendCmt != null){
			//计算 追加评论 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.ACOMMENT, payCoins, spendCoins, lowest);
			task.setNeedAppendCmt(appendCmt);
		}
		
		//设置 是否要求追评晒单
		String appendShow = params.get("append_show");
		if(appendShow != null){
			//计算 追评晒单 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.ASHOW, payCoins, spendCoins, lowest);
			try {
				appendShow = mapper.writeValueAsString(mapper.readValue(appendShow, JsonShow.class));
			} catch (IOException e) {
				return new Result(Errors.PARAM_FORMAT_ERROR, MessageFormat.format(Errors.PARAM_FORMAT_ERROR.getMsg(), "appendShow"));
			}
			task.setNeedAppendShow(appendShow);
		}
				
		//设置 是否规定收货地址
		String receiveddr = params.get("receive_addr");
		if(receiveddr != null){
			//计算 规定收货地址 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.RADDRESS, payCoins, spendCoins, lowest);
			try {
				receiveddr = mapper.writeValueAsString(mapper.readValue(receiveddr, JsonReceiveAddress.class));
			} catch (IOException e) {
				return new Result(Errors.PARAM_FORMAT_ERROR, MessageFormat.format(Errors.PARAM_FORMAT_ERROR.getMsg(), "receive_addr"));
			}
			task.setNeedReceiveAddr(receiveddr);
		}
		
		
		//设置 是否要求分享
		String share = params.get("share");
		if(share != null){
			//计算 分享 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.SHARE, payCoins, spendCoins, lowest);
			task.setNeedShare(share);
		}
		
		//设置 是否要求实名
		String real = params.get("real");
		if(real != null){
			//计算 要求实名消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.REAL, payCoins, spendCoins, lowest);
			task.setNeedReal(real);
		}
				
		//设置 是否要求审核
		String check = params.get("check");
		if(check != null){
			//计算 审核 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.CHECK, payCoins, spendCoins, lowest);
			task.setNeedCheck(check);
		}
		
		//设置 是否要求平台认证
		String safe = params.get("safe");
		if(safe != null){
			//计算 平台认证 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.SAFE, payCoins, spendCoins, lowest);
			task.setNeedSafe(safe);
			
			//获取缴纳保证金比率
			String sdPercent = Memory.SYSTEM_CONFIG.get(Constant.System.ParamName.SECURITY_DEPOSIT_PERCENT);
			//如果为配置则去默认比率
			BigDecimal percent = sdPercent==null || !StringUtil.isNumber(sdPercent)?Constant.System.ParamValue.SECURITY_DEPOSIT_PERCENT:new BigDecimal(sdPercent);
			//计算接手方缴纳保证金
			BigDecimal buyerSecurityDeposit = task.getSellerSecurityDeposit().multiply(percent);
			task.setBuyerSecurityDeposit(buyerSecurityDeposit);
		}
		
		//设置 是否要求旺旺聊天
		String chat = params.get("chat");
		if(chat != null){
			//计算 旺旺聊天 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.CHAT, payCoins, spendCoins, lowest);
			task.setNeedChat(chat);
		}
		
		//设置 是否要真实签收
		String received = params.get("received");
		if(received != null){
			//计算 真实签收 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.RECEIVED, payCoins, spendCoins, lowest);
			task.setNeedReceived(received);
		}
		
		//设置 是否指定接任务地区
		String takeAddr = params.get("take_addr");
		if(takeAddr != null){
			//计算 指定接任务地区 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.TADDRESS, payCoins, spendCoins, lowest);
			try {
				receiveddr = mapper.writeValueAsString(mapper.readValue(receiveddr, JsonAddress.class));
			} catch (IOException e) {
				return new Result(Errors.PARAM_FORMAT_ERROR, MessageFormat.format(Errors.PARAM_FORMAT_ERROR.getMsg(), "take_addr"));
			}
			task.setNeedTakeAddr(takeAddr);
		}
		
		//设置 是否要求货比三家
		String compare = params.get("compare");
		if(compare != null){
			//计算 货比三家 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.COMPARE, payCoins, spendCoins, lowest);
			task.setNeedComment(compare);
		}
		
		//设置 是否要求购买渠道
		String channel = params.get("channel");
		if(channel != null){
			//计算 要求购买渠道 消耗金币
			TaskUtil.countRuleCoins(Constant.Task.Rule.CHANNEL, payCoins, spendCoins, lowest);
			task.setNeedChannel(channel);
		}
		
		//扣除消耗金币
		BigDecimal totalCoins = payCoins.add(spendCoins);
		if(account.getCoins().compareTo(totalCoins) == -1)
			return new Result(CustomErrors.USER_ACCOUNT_ERROR_COINS_NOT_ENOUGH);
		account.setCoins(account.getCoins().subtract(totalCoins));
		
		task.setPayCoins(payCoins);
		task.setSpendCoins(spendCoins);
		task.setTaskIco(icoStr.toString());
		
		String postTimeStr = params.get("postTime");
		Date postTime = new Date();
		if(postTimeStr != null)
			postTime = DateUtil.stringToDateTime(postTimeStr);
		task.setCreatTime(postTime);
		
		serviceDao.getMapper().saveOrUpdate(task, account);
		
		return new Result(Errors.OK);
	}
	
	@ServiceMethod(
		value="cancelTask",
		desc="取消任务",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter(value="task_id", desc="任务ID")
		}
	)
	public Result delTask(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		
		TblTask task = serviceDao.get(TblTask.class, params.get("task_id"));

		if(task == null || !task.getUserId().equals(sessionUser.getUserId()) || !task.getTaskState().equals(Constant.Task.State.WAIT))
			return new Result(CustomErrors.TASK_ERROR_NOT_EXIST);
		
		//将金币和保证金退还给发布者
		TblUserAccount account = serviceDao.get(TblUserAccount.class, task.getUserId());
		account.setBalance(account.getBalance().add(task.getSellerSecurityDeposit()));
		account.setSecurityDeposit(account.getSecurityDeposit().subtract(task.getSellerSecurityDeposit()));
		account.setCoins(account.getCoins().add(task.getSpendCoins()).add(task.getPayCoins()));
		
		serviceDao.getMapper().remove(task);
		serviceDao.getMapper().update(account);
		
		return new Result(Errors.OK);
	}
	
	@ServiceMethod(
		value="resetTask",
		desc="重置任务",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter(value="task_id", desc="任务ID")
		}
	)
	public Result resetTask(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		
		TblTask task = serviceDao.get(TblTask.class, params.get("task_id"));

		if(task == null || !task.getUserId().equals(sessionUser.getUserId()) || (!task.getTaskState().equals(Constant.Task.State.WAIT) && !task.getTaskState().equals(Constant.Task.State.CHECK)))
			return new Result(CustomErrors.TASK_ERROR_NOT_EXIST);
		
		task.setTaskState(Constant.Task.State.WAIT);
		
		//获取接手人列表
		List<TblTaskBidder> bidderList = serviceDao.queryEntityList(
			"select * from tbl_task_bidder where task_id=?",
			TblTaskBidder.class,
			new Object[]{task.getTaskId()}
		);
		
		if(bidderList == null || bidderList.size()==0)
			return new Result(CustomErrors.TASK_ERROR_RESET);
		
		//保证金退还到账户
		StringBuffer sql = new StringBuffer("update tbl_user_account set balance=balance+");
		sql.append(task.getBuyerSecurityDeposit())
		.append(",security_deposit=security_deposit-")
		.append(task.getBuyerSecurityDeposit())
		.append(" where user_id in (");
		for (TblTaskBidder bidder : bidderList) {
			sql.append(bidder.getId().getRecipientUserId()).append(",");
		}
		sql.delete(sql.length() - 1, sql.length()).append(")");
	
		serviceDao.execute("delete from tbl_task_bidder where task_id=?", new Object[]{task.getTaskId()});
		serviceDao.execute(sql.toString());
		
		serviceDao.getMapper().update(task);
		
		return new Result(Errors.OK);
	}
	
	@ServiceMethod(
		value="exitTask",
		desc="退出任务",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter(value="task_id", desc="任务ID")
		}
	)
	public Result exitTask(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		String taskId = params.get("task_id");
		String buyerBizAccount;
		
		TblTask task = serviceDao.get(TblTask.class, taskId);
		if(task == null || (!task.getTaskState().equals(Constant.Task.State.WAIT) && !task.getTaskState().equals(Constant.Task.State.CHECK) && !task.getTaskState().equals(Constant.Task.State.PAY)))
			return new Result(CustomErrors.TASK_ERROR_NOT_EXIST);
		
		List<Object> excuteEntity = new ArrayList<>();
		List<Object> removeEntity = new ArrayList<>();
		
		//如果状态为等待支付
		if(task.getTaskState().equals(Constant.Task.State.PAY)){
			if(!task.getRecipientUserId().equals(sessionUser.getUserId()))
				return new Result(CustomErrors.TASK_ERROR_NOT_EXIST);
			task.setRecipientUserId(null);
			task.setTakeIp(null);
			task.setTakeTime(null);
			task.setTaskState(Constant.Task.State.WAIT);
			
			buyerBizAccount = task.getBuyerBizAccount();
		//剩下状态为等待接手 和 等待审核
		}else{
			TblTaskBidderPK id = new TblTaskBidderPK();
			id.setTaskId(taskId);
			id.setRecipientUserId(sessionUser.getUserId());
			TblTaskBidder bidder = serviceDao.get(TblTaskBidder.class, id);
			if(bidder == null)
				return new Result(CustomErrors.TASK_ERROR_NOT_EXIST);
			removeEntity.add(bidder);
			
			buyerBizAccount = bidder.getBuyerBizAccount();
			if(task.getTaskState().equals(Constant.Task.State.CHECK)){
				task.setTaskState(Constant.Task.State.WAIT);
			}
			
		}
		excuteEntity.add(task);
		
		SimpleDateFormat dateFormat = new SimpleDateFormat(DateFormat.Y_M_D.toString());
		SimpleDateFormat monthFormat = new SimpleDateFormat("yyyy-MM-01");
		Date now = new Date();
		String unlockMonth = monthFormat.format(now);
		
		//IP个数限制-1
		String ip = HttpUtil.getRemoteAddress(request);
		TblTaskIpLimit ipLimit = serviceDao.get(TblTaskIpLimit.class, ip);
		if(ipLimit != null){
			String unlockDate = dateFormat.format(now);
			String ipLimitDate = dateFormat.format(ipLimit.getCreateDate());
			if(ipLimitDate.compareTo(unlockDate) > -1 && ipLimit.getTaskCount() > 0){
				ipLimit.setTaskCount(ipLimit.getTaskCount() - 1);
				excuteEntity.add(ipLimit);
			}
		}
		
		//一个月内接手掌柜任务-1
		TblTaskStoreLimitPK taskStoreLimitId = new TblTaskStoreLimitPK();
		taskStoreLimitId.setBuyerBizAccount(buyerBizAccount);
		taskStoreLimitId.setSellerBizAccount(task.getSellerBizAccount());
		TblTaskStoreLimit taskStoreLimit = serviceDao.get(TblTaskStoreLimit.class, taskStoreLimitId);
		if(taskStoreLimit != null){
			String taskStoreLimitMonth = dateFormat.format(taskStoreLimit.getCreateDate());
			if(taskStoreLimitMonth.compareTo(unlockMonth) > -1 && taskStoreLimit.getTaskCount() > 0){
				taskStoreLimit.setTaskCount(taskStoreLimit.getTaskCount() - 1);
				excuteEntity.add(taskStoreLimit);
			}
			
		}
		
		//同时进行任务-1
		TblUserProgress userProgress = serviceDao.get(
			"select * from tbl_user_progress where user_id=?", 
			TblUserProgress.class,
			new Object[]{sessionUser.getUserId()}
		);
		if(userProgress.getTakingTaskCount() > 0)
			userProgress.setTakingTaskCount(userProgress.getTakingTaskCount() - 1);
		
		//任务类型限制-1
		if(task.getType() == Constant.Task.Type.SHOPPING_CART || task.getType() == Constant.Task.Type.PACKAGE){
			TblTaskTypeLimitPK id = new TblTaskTypeLimitPK();
			id.setBuyerBizAccount(buyerBizAccount);
			id.setSellerBizAccount(task.getSellerBizAccount());
			id.setTaskType(task.getType());
			
			TblTaskTypeLimit taskTypeLimit = serviceDao.get(TblTaskTypeLimit.class, id);
			//如果记录在本月内则删除
			if(taskTypeLimit != null){
				String taskTypeLimitMonth = dateFormat.format(taskTypeLimit.getCreateDate());
				if(taskTypeLimitMonth.compareTo(unlockMonth) > -1)
					removeEntity.add(taskTypeLimit);
			}
		//接手过的商品-1
		}else{
			try {
				List<JsonProduct> productList = mapper.readValue(task.getProductInfo(), new TypeReference<List<JsonProduct>>(){});

				JsonProduct jsonProduct = productList.get(0);
				TblTaskProductLimitPK id = new TblTaskProductLimitPK();
				id.setBizAccount(buyerBizAccount);
				id.setProductId(jsonProduct.getShopId());
				
				TblTaskProductLimit taskProductLimit = serviceDao.get(TblTaskProductLimit.class, id);
				//如果记录在15天内则删除
				if(taskProductLimit != null){
					String taskProductLimitMonth = dateFormat.format(taskProductLimit.getCreateDate());
					String unlockHalfMonth = DateUtil.getAmountDate(Calendar.DATE, -14, "yyyy-MM-dd");
					if(taskProductLimitMonth.compareTo(unlockHalfMonth) == -1)
						removeEntity.add(taskProductLimit);
				}
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
		
		serviceDao.getMapper().remove(removeEntity);
		serviceDao.getMapper().update(excuteEntity);
		return new Result(Errors.OK);
	}
	
	@ServiceMethod(
		value="takeTask",
		desc="接任务",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter(value="task_id", desc="任务ID"),
			@Parameter(value="biz_account", desc="交易买号")
		}
	)
	public Result takeTask(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		String buyerBizAccount = params.get("biz_account");
		String ip = HttpUtil.getRemoteAddress(request);
		
		List<Object> excuteEntity = new ArrayList<>();
		
		TblTask task = serviceDao.get(TblTask.class, params.get("task_id"));
		
		if(task == null || !task.getTaskState().equals(Constant.Task.State.WAIT))
			return new Result(CustomErrors.TASK_ERROR_NOT_EXIST);
		
		task.setTaskState(Constant.Task.State.PAY);
		
		//判断是否为自己
		if(task.getUserId().equals(sessionUser.getUserId()) || task.getSellerBizAccount().equals(buyerBizAccount))
			return new Result(CustomErrors.TASK_ERROR_TAKE_SELF);
		
		//判断IP
		if(task.getPostIp() != null && task.getPostIp().equals(ip))
			return new Result(CustomErrors.TASK_ERROR_TAKE_IP);
		
		//验证买号是否存在
		TblUserBizAccount bizAccount = serviceDao.get(
			"select * from tbl_user_biz_account where user_id=? and biz_account=? and biz_type=?",
			TblUserBizAccount.class, 
			new Object[]{sessionUser.getUserId(), buyerBizAccount, Constant.User.BizAccount.Type.BUYER}
		);
		if(bizAccount == null)
			return new Result(CustomErrors.USER_BIZACCOUNT_ERROR_NOT_EXIST);
		
		//验证是否需要审核接手人
		if(task.getNeedCheck() != null){
			//添加审核名单
			TblTaskBidderPK id = new TblTaskBidderPK();
			id.setTaskId(task.getTaskId());
			id.setRecipientUserId(sessionUser.getUserId());
			TblTaskBidder bidder = serviceDao.get(TblTaskBidder.class, id);
			if(bidder != null)
				return new Result(CustomErrors.TASK_ERROR_TAKE_EXIST);
			bidder = new TblTaskBidder();	
			bidder.setId(id);
			bidder.setIp(ip);
			bidder.setBuyerBizAccount(buyerBizAccount);
			excuteEntity.add(bidder);
			
			TblUserAccount sellerAccount = serviceDao.get(
				"select * from tbl_user_account where user_id=?", 
				new UserAccountRowMapper(),
				new Object[]{task.getUserId()}
			);
			//审核人数上限
			int checkLimit = UserUtil.countRuleNum(sellerAccount.getLevel(), Constant.User.Rule.Type.CHECK_LIMIT);
			
			int count = serviceDao.count(
				"select count(0) from tbl_task_bidder where task_id=?", 
				new Object[]{task.getTaskId()}
			);
			//如果达到上限则不能再接手
			if((count+1) == checkLimit)
				task.setTaskState(Constant.Task.State.CHECK);
			else
				task.setTaskState(Constant.Task.State.WAIT);
		}else{
			if(task.getRecipientUserId().equals(sessionUser.getUserId()))
				return new Result(CustomErrors.TASK_ERROR_TAKE_EXIST);
			task.setRecipientUserId(sessionUser.getUserId());
			task.setTakeIp(ip);
			task.setTakeTime(new Date());
		}
		
		SimpleDateFormat dateFormat = new SimpleDateFormat(DateFormat.Y_M_D.toString());
		SimpleDateFormat monthFormat = new SimpleDateFormat("yyyy-MM-01");
		Date now = new Date();
		String unlockMonth = monthFormat.format(now);
		
		//判断IP个数限制
		//从系统配置中获取IP个数限制
		String ipLimitStr = Memory.SYSTEM_CONFIG.get(Constant.System.ParamName.TASK_IP_LIMIT);
		int ipLimitCount = (ipLimitStr == null || !StringUtil.isInteger(ipLimitStr)?Constant.System.ParamValue.TASK_IP_LIMIT:Integer.parseInt(ipLimitStr));
				
		TblTaskIpLimit ipLimit = serviceDao.get(TblTaskIpLimit.class, ip);
		if(ipLimit != null){
			String unlockDate = dateFormat.format(now);
			String ipLimitDate = dateFormat.format(ipLimit.getCreateDate());
			//如果时间是今天的则判断个数 否则 归零
			if(ipLimitDate.compareTo(unlockDate) > -1){
				if(ipLimit.getTaskCount() >= ipLimitCount)
					return new Result(CustomErrors.TASK_ERROR_TAKE_IP_LIMIT);
			}else{
				ipLimit.setTaskCount(0);
			}
		}else{
			ipLimit = new TblTaskIpLimit();
			ipLimit.setIp(ip);
		}
		ipLimit.setCreateDate(new Date());
		ipLimit.setTaskCount(ipLimit.getTaskCount() + 1);
		excuteEntity.add(ipLimit);
		
		//判断一个月内接手掌柜任务数量
		String storeLimitStr = Memory.SYSTEM_CONFIG.get(Constant.System.ParamName.TASK_STORE_LIMIT);
		int storeLimit = (storeLimitStr == null || !StringUtil.isInteger(storeLimitStr)?Constant.System.ParamValue.TASK_STORE_LIMIT:Integer.parseInt(storeLimitStr));
		
		TblTaskStoreLimitPK taskStoreLimitId = new TblTaskStoreLimitPK();
		taskStoreLimitId.setBuyerBizAccount(buyerBizAccount);
		taskStoreLimitId.setSellerBizAccount(task.getSellerBizAccount());
		
		TblTaskStoreLimit taskStoreLimit = serviceDao.get(TblTaskStoreLimit.class, taskStoreLimitId);
		if(taskStoreLimit != null){
			String taskStoreLimitMonth = dateFormat.format(taskStoreLimit.getCreateDate());
			//如果时间在本月内则判断个数 否则 归零
			if(taskStoreLimitMonth.compareTo(unlockMonth) > -1){
				if(taskStoreLimit.getTaskCount() >= storeLimit)
					return new Result(CustomErrors.TASK_ERROR_TAKE_SELLER_LIMIT, String.format(CustomErrors.TASK_ERROR_TAKE_SELLER_LIMIT.getMsg(), storeLimit));
			}else{
				taskStoreLimit.setTaskCount(0);
			}
		}else{
			taskStoreLimit = new TblTaskStoreLimit();
			taskStoreLimit.setId(taskStoreLimitId);
		}
		taskStoreLimit.setCreateDate(new Date());
		taskStoreLimit.setTaskCount(taskStoreLimit.getTaskCount() + 1);//数量+1
		excuteEntity.add(taskStoreLimit);
		
		//判断同时接任务个数上限
		TblUserAccount buyerAccount = serviceDao.get(
			"select * from tbl_user_account where user_id=?", 
			new UserAccountRowMapper(),
			new Object[]{sessionUser.getUserId()}
		);
		TblUserProgress userProgress = serviceDao.get(
			"select * from tbl_user_progress where user_id=?", 
			TblUserProgress.class,
			new Object[]{sessionUser.getUserId()}
		);
		int taskLimit = UserUtil.countRuleNum(buyerAccount.getLevel(), Constant.User.Rule.Type.TASK_LIMIT);
		if(userProgress.getTakingTaskCount() >= taskLimit)
			return new Result(CustomErrors.TASK_ERROR_TAKE_LIMIT);
		userProgress.setTakingTaskCount(userProgress.getTakingTaskCount() + 1);//正在进行任务+1
		
		//判断一个月内是否接手过掌柜的购物车任务或者套餐任务
		if(task.getType() == Constant.Task.Type.SHOPPING_CART || task.getType() == Constant.Task.Type.PACKAGE){
			TblTaskTypeLimitPK id = new TblTaskTypeLimitPK();
			id.setBuyerBizAccount(buyerBizAccount);
			id.setSellerBizAccount(task.getSellerBizAccount());
			id.setTaskType(task.getType());
			
			TblTaskTypeLimit taskTypeLimit = serviceDao.get(TblTaskTypeLimit.class, id);
			if(taskTypeLimit != null){
				String taskTypeLimitMonth = dateFormat.format(taskTypeLimit.getCreateDate());
				//如果时间在本月内不可接取
				if(taskTypeLimitMonth.compareTo(unlockMonth) > -1)
					return new Result(CustomErrors.TASK_ERROR_TAKE_TYPE_REPEAT);
			}else{
				taskTypeLimit = new TblTaskTypeLimit();
				taskTypeLimit.setId(id);
			}
			taskTypeLimit.setCreateDate(new Date());
			excuteEntity.add(taskTypeLimit);
		}else{
			//判断15天内是否接手过该商品
			try {
				List<JsonProduct> productList = mapper.readValue(task.getProductInfo(), new TypeReference<List<JsonProduct>>(){});

				JsonProduct jsonProduct = productList.get(0);
				TblTaskProductLimitPK id = new TblTaskProductLimitPK();
				id.setBizAccount(buyerBizAccount);
				id.setProductId(jsonProduct.getShopId());
				
				TblTaskProductLimit taskProductLimit = serviceDao.get(TblTaskProductLimit.class, id);
				if(taskProductLimit != null){
					String taskProductLimitMonth = dateFormat.format(taskProductLimit.getCreateDate());
					String unlockHalfMonth = DateUtil.getAmountDate(Calendar.DATE, -14, "yyyy-MM-dd");
					//如果15天内则不可接取
					if(taskProductLimitMonth.compareTo(unlockHalfMonth) == -1)
						return new Result(CustomErrors.TASK_ERROR_TAKE_PRODUCT_REPEAT);
				}else{
					taskProductLimit = new TblTaskProductLimit();
					taskProductLimit.setId(id);
				}
				taskProductLimit.setCreateDate(new Date());
				excuteEntity.add(taskProductLimit);
				
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	
		//验证是否需要实名
		if(task.getNeedReal() != null){
			if(bizAccount.getRealFlag() == Constant.System.RealFlag.N)
				return new Result(CustomErrors.USER_BIZACCOUNT_ERROR_NOT_REAL);
		}
		
		//验证是需要保证金
		if(task.getNeedSafe() != null){
			TblUserAccount account = serviceDao.get(TblUserAccount.class, sessionUser.getUserId());
			
			//比较是否达到对应保证金额
			if(task.getBuyerSecurityDeposit().compareTo(account.getBalance()) == -1){
				return new Result(CustomErrors.USER_ACCOUNT_ERROR_BALANCE_NOT_ENOUGH);
			}
			
			//扣除接手方账户余额转到保证金
			account.setBalance(account.getBalance().subtract(task.getBuyerSecurityDeposit()));
			account.setSecurityDeposit(account.getSecurityDeposit().add(task.getBuyerSecurityDeposit()));
			excuteEntity.add(account);
		}
		
		//验证是需要指定接任务地区
		if(task.getNeedTakeAddr() != null){
			try {
				JsonIPInfo ipInfo = UserUtil.getAddress(HttpUtil.getRemoteAddress(request));
				JsonAddress taskAddress = mapper.readValue(task.getNeedTakeAddr(), JsonAddress.class);
				
				if(taskAddress.getCity() != null && !taskAddress.getCity().contains(ipInfo.getCity()))
					return new Result(CustomErrors.TASK_ERROR_TAKE_CITY);
				if(taskAddress.getProvince() != null && !taskAddress.getProvince().contains(ipInfo.getProvince()))
					return new Result(CustomErrors.TASK_ERROR_TAKE_PROVINCE);
				
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		excuteEntity.add(task);
		excuteEntity.add(userProgress);
		
		serviceDao.getMapper().saveOrUpdate(excuteEntity);
		
		return new DataResult(Errors.OK, new Data(task));
	}
	
	@ServiceMethod(
		value="checkTask",
		desc="审核任务",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter(value="task_id", desc="任务ID"),
			@Parameter(value="buyer_user_id", desc="接手用户ID"),
			@Parameter(value="biz_account", desc="交易买号")
		}
	)
	public Result checkTask(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		String buyerUserId = params.get("buyer_user_id");
		String bizAccount = params.get("biz_account");
		
		TblTask task = serviceDao.get(TblTask.class, params.get("task_id"));

		if(task == null || !task.getUserId().equals(sessionUser.getUserId()) || !task.getTaskState().equals(Constant.Task.State.CHECK))
			return new Result(CustomErrors.TASK_ERROR_NOT_EXIST);
		task.setRecipientUserId(buyerUserId);
		task.setBuyerBizAccount(bizAccount);
		task.setTaskState(Constant.Task.State.PAY);
		
		StringBuffer userIds = new StringBuffer("(");
		StringBuffer buyerBizAccounts = new StringBuffer("(");
		StringBuffer ips = new StringBuffer("(");
		
		//获取接手人列表
		List<TblTaskBidder> bidderList = serviceDao.queryEntityList(
			"select * from tbl_task_bidder where task_id=?",
			TblTaskBidder.class,
			new Object[]{task.getTaskId()}
		);
		boolean exist = false;
		for (TblTaskBidder bidder : bidderList) {
			if(bidder.getId().getRecipientUserId().equals(buyerUserId) && bidder.getBuyerBizAccount().equals(bizAccount)){
				exist = true;
				task.setTakeIp(bidder.getIp());
				task.setTakeTime(new Date());
			}else{
				userIds.append(bidder.getId().getRecipientUserId()).append(",");
				buyerBizAccounts.append(bidder.getBuyerBizAccount()).append(",");
				ips.append(bidder.getIp()).append(",");
			}
		}
		userIds.delete(userIds.length() - 1, userIds.length()).append(")");
		buyerBizAccounts.delete(buyerBizAccounts.length() - 1, buyerBizAccounts.length()).append(")");
		ips.delete(ips.length() - 1, ips.length()).append(")");
		
		//判断接手人是否存在
		if(!exist)
			return new Result(CustomErrors.USER_BIZACCOUNT_ERROR_NOT_EXIST);
		
		//把淘汰的接手人保证金退还到账户
		StringBuffer sql = new StringBuffer("update tbl_user_account set balance=balance+");
		sql.append(task.getBuyerSecurityDeposit())
		.append(",security_deposit=security_deposit-")
		.append(task.getBuyerSecurityDeposit())
		.append(" where user_id in ").append(userIds);
		serviceDao.execute(sql.toString());
		
		SimpleDateFormat dateFormat = new SimpleDateFormat(DateFormat.Y_M_D.toString());
		SimpleDateFormat monthFormat = new SimpleDateFormat("yyyy-MM-01");
		Date now = new Date();
		String unlockMonth = monthFormat.format(now);
		
		//IP个数限制-1
		sql.setLength(0);
		String unlockDate = dateFormat.format(now);
		sql.append("update tbl_task_ip_limit set task_count=task_count-1 where task_count>0 and create_date>=? and ip in ")
		.append(ips.toString());
		serviceDao.execute(sql.toString(), new Object[]{unlockDate});
		
		//一个月内接手掌柜任务-1
		sql.setLength(0);
		sql.append("update tbl_task_store_limit set task_count=task_count-1 where seller_biz_account=? and task_count>0 and create_date >=? and buyer_biz_account in ")
		.append(buyerBizAccounts);
		serviceDao.execute(sql.toString(), new Object[]{task.getSellerBizAccount(), unlockMonth});

		//同时进行任务-1
		sql.setLength(0);
		sql.append("update tbl_user_progress set taking_task_count=taking_task_count-1 where taking_task_count>0 and user_id in ")
		.append(userIds);
		serviceDao.execute(sql.toString());
		
		//任务类型限制-1
		sql.setLength(0);
		if(task.getType() == Constant.Task.Type.SHOPPING_CART || task.getType() == Constant.Task.Type.PACKAGE){
			sql.append("delete from tbl_task_type_limit where create_date>=? and task_type=? and seller_biz_account=? and buyer_biz_account in ")
			.append(buyerBizAccounts);
			serviceDao.execute(sql.toString(), new Object[]{unlockMonth, task.getType(), task.getSellerBizAccount()});
		//接手过的商品-1
		}else{
			try {
				List<JsonProduct> productList = mapper.readValue(task.getProductInfo(), new TypeReference<List<JsonProduct>>(){});
				JsonProduct jsonProduct = productList.get(0);
				
				String unlockHalfMonth = DateUtil.getAmountDate(Calendar.DATE, -14, "yyyy-MM-dd");
				sql.append("delete from tbl_task_product_limit where product_id=? and create_date<? and buyer_biz_account in ")
				.append(buyerBizAccounts);
				serviceDao.execute(sql.toString(), new Object[]{jsonProduct.getShopId(), unlockHalfMonth});
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
		
		serviceDao.execute("delete from tbl_task_bidder where task_id=?", new Object[]{task.getTaskId()});
		serviceDao.getMapper().update(task);
		
		return new Result(Errors.OK);
	}
	
	@ServiceMethod(
		value="payTask",
		desc="确认支付",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter(value="task_id", desc="任务ID")
		}
	)
	public Result payTask(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		
		TblTask task = serviceDao.get(TblTask.class, params.get("task_id"));
		
		if(task == null || !task.getRecipientUserId().equals(sessionUser.getUserId()) || !task.getTaskState().equals(Constant.Task.State.PAY))
			return new Result(CustomErrors.TASK_ERROR_NOT_EXIST);
		//任务状态变为 等待发货
		task.setTaskState(Constant.Task.State.SEND);
		
		serviceDao.getMapper().update(task);
		
		return new Result(Errors.OK);
	}
	
	@ServiceMethod(
		value="sendTask",
		desc="确认发货",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter(value="task_id", desc="任务ID")
		}
	)
	public Result sendTask(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		
		TblTask task = serviceDao.get(TblTask.class, params.get("task_id"));
	
		if(task == null || !task.getUserId().equals(sessionUser.getUserId()) || !task.getTaskState().equals(Constant.Task.State.SEND))
			return new Result(CustomErrors.TASK_ERROR_NOT_EXIST);
		
		//任务状态变为 等待好评
		if(task.getNeedShow() != null)
			task.setTaskState(Constant.Task.State.COMMENT_SHOW);
		else
			task.setTaskState(Constant.Task.State.COMMENT);
		
		serviceDao.getMapper().update(task);
		
		return new Result(Errors.OK);
	}
	
	@ServiceMethod(
		value="promptTask",
		desc="确认好评",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter(value="task_id", desc="任务ID")
		}
	)
	public Result promptTask(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);

		TblTask task = serviceDao.get(TblTask.class, params.get("task_id"));
		
		if(task == null || !task.getRecipientUserId().equals(sessionUser.getUserId()) || (!task.getTaskState().equals(Constant.Task.State.COMMENT) && !task.getTaskState().equals(Constant.Task.State.COMMENT_SHOW)))
			return new Result(CustomErrors.TASK_ERROR_NOT_EXIST);
		
		//任务状态变为 等待确认
		task.setTaskState(Constant.Task.State.CONFIRM);
		
		serviceDao.getMapper().update(task);
		
		return new Result(Errors.OK);
	}
	
	@ServiceMethod(
		value="confirmTask",
		desc="确认任务",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter(value="task_id", desc="任务ID")
		}
	)
	public Result confirmTask(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		List<Object> excuteEntity = new ArrayList<>();
		
		TblTask task = serviceDao.get(TblTask.class, params.get("task_id"));
		
		if(task == null || !task.getUserId().equals(sessionUser.getUserId()) || !task.getTaskState().equals(Constant.Task.State.CONFIRM))
			return new Result(CustomErrors.TASK_ERROR_NOT_EXIST);
		
		//任务状态变为 任务完成
		task.setTaskState(Constant.Task.State.COMPLETE);
		
		//从系统配置中获取成长积分值
		String creditStr = Memory.SYSTEM_CONFIG.get(Constant.System.ParamName.GROW_CREDIT);
		int credit = (creditStr == null || !StringUtil.isInteger(creditStr)?Constant.System.ParamValue.GROW_CREDIT:Integer.parseInt(creditStr));
		//买家保证金返还,金币,积分增加
		TblUserAccount buyerAccount = serviceDao.get(TblUserAccount.class, task.getRecipientUserId());
		/**将保证金存放到 保证金列表 3个月后返还.... 代码...*/
		//buyerAccount.setBalance(buyerAccount.getBalance().add(task.getBuyerSecurityDeposit()).add(task.getSellerSecurityDeposit()));
		//buyerAccount.setSecurityDeposit(buyerAccount.getSecurityDeposit().subtract(task.getBuyerSecurityDeposit()));
		buyerAccount.setCoins(buyerAccount.getCoins().add(task.getPayCoins()));
		buyerAccount.setCredit(buyerAccount.getCredit() + credit);
		excuteEntity.add(buyerAccount);
		
		//使用次数增加
		TblUserBizAccount buyerBizAccount = serviceDao.get(
			"select * from tbl_user_biz_account where user_id=? and biz_account=? and biz_type=?",
			TblUserBizAccount.class, 
			new Object[]{task.getRecipientUserId(), task.getBuyerBizAccount(), Constant.User.BizAccount.Type.BUYER}
		);
		buyerBizAccount.setUseCount(buyerBizAccount.getUseCount() + 1);
		excuteEntity.add(buyerBizAccount);
		
		//卖家积分增加
		TblUserAccount sellerAccount = serviceDao.get(TblUserAccount.class, task.getUserId());
		sellerAccount.setCredit(sellerAccount.getCredit() + credit);
		excuteEntity.add(sellerAccount);
			
		//买家同时接任务个数-1
		TblUserProgress userProgress = serviceDao.get(TblUserProgress.class, task.getRecipientUserId());
		if(userProgress.getTakingTaskCount() > 0){
			userProgress.setTakingTaskCount(userProgress.getTakingTaskCount() - 1);
			userProgress.setCompleteTaskCount(userProgress.getCompleteTaskCount() + 1);
			excuteEntity.add(userProgress);
		}
		
		serviceDao.getMapper().saveOrUpdate(excuteEntity);
		
		return new Result(Errors.OK);
	}
	
	
	@ServiceMethod(
		value="getBidderList",
		desc="获取接手人列表",
		params={
			@Parameter(type=TokenParam.class),
			@Parameter(value="task_id", desc="任务ID")
		}
	)
	public Result getBidderList(HttpServletRequest request, Map<String,String> params) {
		TblUser sessionUser = Memory.getSessionUser(request);
		
		QueryBuilder builder = new QueryBuilder(
			"select bidder.*,(select count(0) from tbl_user_blacklist where black_user_id=bidder.recipient_user_id) black_count,u.user_type,account.credit,info.address,biz_account.biz_account,biz_account.real_flag,biz_account.use_count,biz_account.info_url " +
			"from tbl_task_bidder bidder " +
			"left join tbl_user u on bidder.recipient_user_id = u.user_id " +
			"left join tbl_user_info info on bidder.recipient_user_id=info.user_id " +
			"left join tbl_user_account account on bidder.recipient_user_id=account.user_id " +
			"left join tbl_user_biz_account biz_account on bidder.buyer_biz_account=biz_account.biz_account",
			new Condition(
				new SqlColumn(Logic.WHERE, "bidder.task_id").equal(params.get("task_id")),
				new SqlColumn("bidder.user_id").equal(sessionUser.getUserId())
			),
			new Profile(params)
		);
		
		DataResult result = serviceDao.queryForDataResult(builder, new BidderRowMapper());
		
		return result;
	}
	
	public IServiceDao getServiceDao() {
		return serviceDao;
	}
	
	public void setServiceDao(IServiceDao serviceDao) {
		this.serviceDao = serviceDao;
	}
	
	public static void main(String[] args) throws Exception {
		ObjectMapper mapper = new ObjectMapper();
		mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
		mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
		JsonSellerPrompt sellerPromp = mapper.readValue("{count:5, 'server':'电信一区'}", JsonSellerPrompt.class);
		System.out.println(mapper.writeValueAsString(sellerPromp));
		
		List<JsonProduct> productList = mapper.readValue("[{'price':123,'url':'asdfasdf'},{}]", new TypeReference<List<JsonProduct>>(){});
		JsonProduct jp =productList.get(0);
		jp.setUrl("1111111");
		System.out.println(productList.size());
		System.out.println(mapper.writeValueAsString(productList));
	}
}
